package w4156.idog.server;

import java.util.*;
import java.util.Map.Entry;

import javax.ejb.Stateful;
import javax.ejb.TransactionAttribute;
import javax.ejb.TransactionAttributeType;
import javax.naming.InitialContext;
import javax.persistence.EntityNotFoundException;

import w4156.idog.model.Card;
import w4156.idog.model.User;
import w4156.idog.model.User.statusType;

/**
 * Session Bean implementation class TransactionManagerBean
 */
@Stateful(mappedName = "ejb/eBlackjack/TransMgrSLSB")
public class TransactionManagerBean implements TransactionManagerBeanRemote {

	
	private static HashMap<Integer, TransactionSessionBeanRemote> gameMap;
	private static HashMap<Integer, String> sessionMap;
	
	private static PlayerManagerBeanRemote playerMgr;
	private int Max_Number = 4;
	private int tableNumber = 0;
	private static List<User> usersList;
	
    /**
     * Default constructor. 
     */
    static {
        try {
        	gameMap = new HashMap<Integer,TransactionSessionBeanRemote>();
        	sessionMap = new HashMap<Integer, String>();
        	usersList = new ArrayList<User>();
//        	playerMgr = null;
    		InitialContext context = new InitialContext();
    		playerMgr = (PlayerManagerBeanRemote) context.lookup("ejb/eBlackjack/PlayerManagerSLSB");
        } catch (Exception e) {
            e.printStackTrace();
        }
	}

	@Override
	public User authenticate(String username, String password, String sessionId){
		List<User> tmp = null;
		tmp = playerMgr.findByName(username);
		User user = null;
		if (tmp.size() != 0) {
			user = tmp.get(0);
			if (user.getPassword().compareTo(password) == 0) {

				if (!usersList.contains(user)) {
					usersList.add(user);
					System.out.println(usersList.size());
				}
				else
					surrender(user.getObjid(), sessionMap.get(user.getObjid()));
				sessionMap.put(user.getObjid(), sessionId);
				return user;
			}
			return null;
		}
		
    	/*angeIterator<Entry<Integer, TransactionSessionBeanRemote>> it=gameMap.entrySet().iterator();
    	while(it.hasNext()){
    		TransactionSessionBeanRemote tmpTable = it.next().getValue();
    		if (tmpTable.contains(user.getObjid())){
    			return null;
    		}
    	}*/
//		throw new RuntimeException("Incorrect login info");
		return null;
	}
	
    @Override
    public Card bid(int userId, double money, String sessionId){
    	if (!checkSession(userId, sessionId))
    		throw new RuntimeException("Session expired!");
    	
    	Card aCard = null;
    	
    	Iterator<Entry<Integer, TransactionSessionBeanRemote>> it=gameMap.entrySet().iterator();
    	while(it.hasNext()){
    		TransactionSessionBeanRemote tmpTable = it.next().getValue();
    		if (tmpTable.contains(userId)){
    			System.out.println("bid "+userId+" "+money);
    			aCard = tmpTable.bidOp(userId, money);
    			break;
    		}
    	}
		return aCard;
    }
	
    private boolean checkSession(int userId, String sessionId) {

    	String storedSession = sessionMap.get(userId);
    	if (storedSession == null || storedSession.compareToIgnoreCase(sessionId) != 0)
    		return false;

    	return true;
	}
	
    @Override
	public int createUser(User user, String sessionId){
    	if (user.getMoney() == null)
    		user.setMoney(0.0);
    	return playerMgr.createUser(user);
	}
	
	/**
     * Delete the user when user is not online
     * @param user
     */
	public void deleteUser(User user, String sessionId){
		int id = user.getObjid();
		System.out.println("<EJB TMB> deleting user id: " + id);
		if (getUser(id, sessionId) != null)
			throw new ConcurrentModificationException("Can't delete online user!");
		playerMgr.delete(user);
	}
    
    /*
     * Take another card
     * @return the drew card
     */
    @Override
    public Card doubleDown(int userId, String sessionId){
    	if (!checkSession(userId, sessionId))
//    		throw new RuntimeException("Session expired!");
    		return null;

    	Card aCard = null;
    	
    	Iterator<Entry<Integer, TransactionSessionBeanRemote>> it=gameMap.entrySet().iterator();
    	while(it.hasNext()){
    		TransactionSessionBeanRemote tmpTable = it.next().getValue();
    		if (tmpTable.contains(userId)){
    			aCard = tmpTable.doubleOp(userId);
    			break;
    		}
    	}
		return aCard;
    }
    
    @Override
	public List<Card> getCardList(int userId, String sessionId) {
    	if (!checkSession(userId, sessionId))
//    		throw new RuntimeException("Session expired!");
    		return null;

    	Iterator<Entry<Integer, TransactionSessionBeanRemote>> it=gameMap.entrySet().iterator();
    	while(it.hasNext()){
    		TransactionSessionBeanRemote tmpTable = it.next().getValue();
    		if (tmpTable.contains(userId)){
    			return tmpTable.getCards(userId);
    		}
    	}
		
		return null;
	}
    
   
    public int getTableId(int userId){
    	Iterator<Entry<Integer, TransactionSessionBeanRemote>> it=gameMap.entrySet().iterator();
    	while(it.hasNext()){
    		Entry<Integer, TransactionSessionBeanRemote> tsb = it.next();
    		if (tsb.getValue().contains(userId)){
    			return tsb.getKey();
    		}
    	}
		return -1;
    }
    
    /*
     * return the current player lists in particular table
     */
    @Override
    public User getUser(int userId, String sessionId){
    	if (!checkSession(userId, sessionId))
    		return null;
    	
    	Iterator<User> itor=usersList.iterator();
    	User tmpuser = null;
    	boolean founduser = false;
    	
    	while(itor.hasNext()){
    		tmpuser = itor.next();
    		System.out.println(tmpuser.getName()+tmpuser.getObjid());
    		if (tmpuser.getObjid() == userId){
    			founduser = true;
    			System.out.println("find user!!!!"+userId);
    			break;
    		}
    	}
    	
    	if (!founduser){
    		System.out.println("can not find user!!!!");
    		return null;
    	}
    	return tmpuser;
    }
    
    @Override
	@TransactionAttribute(TransactionAttributeType.REQUIRED)
	public List<User> getUserList(int userId, String sessionId) {
    	System.out.println("<EJB> get user List entering...");
    	if (!checkSession(userId, sessionId))
//    		throw new RuntimeException("Session expired!");
    		return null;

		List<User> users = new ArrayList<User>();
/*		User u = new User();
		u.setName("TEST TEST");
		users.add(u);
		if (true) return users;*/
		
		/*
		 * Find if current user is administrator
		 * If true, return all user list in the database.
		 */
		User user = playerMgr.findByPK(userId);
		if (user == null)
			throw new EntityNotFoundException("Illegal user!");
		if (user.isAdmin()) {
			return playerMgr.findAllContacts();
		}
		
    	Iterator<Entry<Integer, TransactionSessionBeanRemote>> it=gameMap.entrySet().iterator();
    	while(it.hasNext()){
    		TransactionSessionBeanRemote tmpTable = it.next().getValue();
    		if (tmpTable.contains(userId)){
    			users = tmpTable.getUsers(userId);
    			int i = 0;
    			if (tmpTable.isWin() && !tmpTable.isSaved()) {
    				while (i < users.size()) {
    					if (users.get(i).getName().compareToIgnoreCase("dealer") != 0) {
    						playerMgr.save(users.get(i));
    					}
    					i++;
    				}
    				tmpTable.setSaved(true);
    			}
    	    	System.out.println("<EJB> get user List size: " + users.size());

    			return users;
    		}
    	}
		
		return null;
	}
    
    /*
     * Take another card
     * @return the drew card
     */
    @Override
    public Card hit(int userId, String sessionId){
    	if (!checkSession(userId, sessionId))
//    		throw new RuntimeException("Session expired!");
    		return null;
    	
    	Card aCard = null;
    	
    	Iterator<Entry<Integer, TransactionSessionBeanRemote>> it=gameMap.entrySet().iterator();
    	while(it.hasNext()){
    		TransactionSessionBeanRemote tmpTable = it.next().getValue();
    		if (tmpTable.contains(userId)){
    			aCard = tmpTable.hitOp(userId);
    			break;
    		}
    	}
		return aCard;
    }

	@Override
	public boolean isAdmin(int userId, String sessionId) {
    	if (!checkSession(userId, sessionId))
//    		throw new RuntimeException("Session expired!");
    		return false;
		return playerMgr.isAdmin(userId);	

	}

	/**
	 * @return a table id when user successfully join a game
	 * @reference http://en.wikipedia.org/wiki/Blackjack
	 */
    @Override
    public boolean joinTable(int userId, String sessionId){
    	System.out.println("Input sessionId: " + sessionId);
    	System.out.println("Saved sessionId: " + sessionMap.get(userId));
    	if (!checkSession(userId, sessionId))
//    		throw new RuntimeException("Session expired!");
    		return false;
    	//User tmpuser = playerMgr.findByPK(userId);
    	
    	
    	Iterator<User> itor=usersList.iterator();
    	User tmpuser = null;
    	boolean founduser = false;
    	
    	while(itor.hasNext()){
    		tmpuser = itor.next();
    		System.out.println(tmpuser.getName()+tmpuser.getObjid());
    		if (tmpuser.getObjid() == userId){
    			founduser = true;
//    			System.out.println("find user!!!!"+userId);
    			break;
    		}
    	}
    	
    	if (!founduser){
//    		System.out.println("can not find user!!!!");
    		return false;
    	}
    	
    	boolean found = false;
    	Iterator<Entry<Integer, TransactionSessionBeanRemote>> it=gameMap.entrySet().iterator();

    	while(it.hasNext()){
    		TransactionSessionBeanRemote tmp = it.next().getValue();
    		if (tmp.getPlayerNumber() < Max_Number){
    			if (tmp.isWin()) {
    				continue;
    			}
//    			System.out.println("find a table!!!!");
    			
    			tmpuser.setStatus(statusType.Pending);
    			tmp.insert(tmpuser);
    			found = true;
//    			System.out.println("insert in the table!!!! "+tmpuser.getObjid());
    			break;
    		}
    	}

    	//new game table
    	if (found==false){
            try {
            	TransactionSessionBeanRemote game = null;
        		System.out.println("new game!!!!");

        		InitialContext context = new InitialContext();
        		game = (TransactionSessionBeanRemote) context.lookup("ejb/eBlackjack/TransactionSLSB");
        		//game = new TransactionSessionBean();
        		System.out.println("new game 1");
        		tmpuser.setStatus(statusType.Pending);
        		game.insert(tmpuser);
        		System.out.println("new game 2");
        		gameMap.put(tableNumber, game);
        		System.out.println("new game 3");
        		
        		//CardsManagerBean cardMgr = null;
        		//cardMgr = (CardsManagerBean) context
        		//		.lookup("ejb/eBlackjack/CardsMgrSLSB");
        		//game.setCards(cardMgr.getcards(tableNumber));
        		tableNumber++;
        		System.out.println("new game"+tableNumber);
            } catch (Exception e) {
                e.printStackTrace();
            }
    	}
		//return tableNumber;
		return true;
    }
	
	@Override
	public void logout(int userId, String sessionId){
    	if (!checkSession(userId, sessionId))
//    		throw new RuntimeException("Session expired!");
    		return;
    	
    	User tmpuser = null;
    	
    	boolean found = false;
    	Iterator<Entry<Integer, TransactionSessionBeanRemote>> it=gameMap.entrySet().iterator();

    	while(it.hasNext()){
    		Entry<Integer, TransactionSessionBeanRemote> tmpPair = it.next();
    		TransactionSessionBeanRemote tmp = tmpPair.getValue();
    		Integer tmpi = tmpPair.getKey();
    		
    		if (tmp.contains(userId)){
    			if (tmp.isWin()) {
    				try {
    					gameMap.remove(tmpi);
    					tmp.remove();
    				}catch (Exception e) {};
    				tmp = null;
    				continue;
    			}
    			else {
    				List<UserSessionRemote> tableusers = tmp.getTableUsers();
    				Iterator<UserSessionRemote> itor=tableusers.iterator();
    		    	while(itor.hasNext()){
    		    		UserSessionRemote tmpUserSession = itor.next();
    		    		if (tmpUserSession.getUser().getObjid() == userId){
    		    			if (tmp.getCurrent() == userId) {
    		    				tmp.surrenderOp(userId);
    		    			}
    		    			else {
    		    				tmpUserSession.setStatus(statusType.Surrender);
    		    			}
    		    			break;
    		    		}
    		    	}
    		    	break;
    			}
    		}
    	}
    	
    	Iterator<User> itor=usersList.iterator();
    	tmpuser = null;
    	boolean founduser = false;

    	sessionMap.remove(userId);
    	
    	while(itor.hasNext()){
    		tmpuser = itor.next();
    		System.out.println(tmpuser.getName()+tmpuser.getObjid());
    		if (tmpuser.getObjid() == userId){
    			founduser = true;
//    			System.out.println("logout!!!!"+userId);
    			usersList.remove(tmpuser);
    			tmpuser.setStatus(statusType.Pending);
    			break;
    		}
    	}
    	
    	if (!founduser){
    		System.out.println("can not find user!!!!");
    	}
    	return;
	}

	@Override
	public void modifyUser(User user, String sessionId) {
		if (getUser(user.getObjid(), sessionId) != null)
			throw new ConcurrentModificationException("Can't modify online user!");
		playerMgr.ModifyUser(user);	}
	
	
    public void setMyTurn(int userId) {
    	Iterator<Entry<Integer, TransactionSessionBeanRemote>> it=gameMap.entrySet().iterator();
    	while(it.hasNext()){
    		TransactionSessionBeanRemote tmpTable = it.next().getValue();
    		if (tmpTable.contains(userId)){
    			tmpTable.setMyTurn();
    			break;
    		}
    	}
	}

	@Override
	public void setReady(int userId, String sessionId) {
    	if (!checkSession(userId, sessionId))
//    		throw new RuntimeException("Session expired!");
    		return;

    	Iterator<Entry<Integer, TransactionSessionBeanRemote>> it=gameMap.entrySet().iterator();
    	while(it.hasNext()){
    		System.out.println("setReady");
    		TransactionSessionBeanRemote tmpTable = it.next().getValue();
    		if (tmpTable.contains(userId)){
    			tmpTable.setReady(userId);
    			break;
    		}
    	}
	}

	/*
     * Take no more card
     */
    @Override
    public void stand(int userId, String sessionId){
    	if (!checkSession(userId, sessionId))
//    		throw new RuntimeException("Session expired!");
    		return;

    	Iterator<Entry<Integer, TransactionSessionBeanRemote>> it=gameMap.entrySet().iterator();
    	while(it.hasNext()){
    		TransactionSessionBeanRemote tmpTable = it.next().getValue();
    		if (tmpTable.contains(userId)){
    			tmpTable.standOp(userId);
    			break;
    		}
    	}
		return;
}
	
	@Override
    public void surrender(int userId, String sessionId){
    	if (!checkSession(userId, sessionId))
//    		throw new RuntimeException("Session expired!");
    		return;

    	Iterator<Entry<Integer, TransactionSessionBeanRemote>> it=gameMap.entrySet().iterator();
    	while(it.hasNext()){
    		TransactionSessionBeanRemote tmpTable = it.next().getValue();
    		if (tmpTable.contains(userId)){
    			tmpTable.surrenderOp(userId);
    			break;
    		}
    	}
		return;
    }
}
